﻿using Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;

namespace ED.Cousul
{
    public static class CousulExtensions
    {
        public static IServiceCollection AddConsul(this IServiceCollection services, Action<AppCousulConfig>? setupAction = null)
        {
            var configuration = services.BuildServiceProvider().GetService<IConfiguration>();
            var consulConfig = new AppCousulConfig();
            configuration.GetSection("ConsulServer").Bind(consulConfig);
            services.Configure<AppCousulConfig>(t => 
            {
                t.Address = consulConfig.Address;
                t.Port = consulConfig.Port;
                t.Interval = consulConfig.Interval;
                t.HealCheckUrl = consulConfig.HealCheckUrl;
                t.Id = Guid.NewGuid().ToString();
                t.Name = consulConfig.Name;
                t.Scheme = consulConfig.Scheme;
                t.ServiceUrl = consulConfig.ServiceUrl;
                t.Timeout = consulConfig.Timeout;
                t.DeregisterCriticalServiceAfter = consulConfig.DeregisterCriticalServiceAfter;
            });
            if (setupAction != null)
            {
                services.Configure(setupAction);

            }
            services.AddSingleton<IServiceDisConver, ServiceDisConver>();
            // var config = services.BuildServiceProvider().GetService<IOptions<AppCousulConfig>>();
            return services;
        }

        public static IApplicationBuilder UseConsul(this IApplicationBuilder app)
        {
            var config = new AppCousulConfig();
            using (var scope = app.ApplicationServices.CreateScope())
            {
                config = scope.ServiceProvider.GetRequiredService<IOptions<AppCousulConfig>>().Value;
            }
            var lifetime = app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>();
            var consulClient = new ConsulClient(x =>
            {
                // consul 服务地址(你要注册到哪个consul服务就填写哪个)
                x.Address = new Uri(config?.ServiceUrl ?? "http://127.0.0.1:8500");
            });

            // 是否进行健康检查 GRPC使用TCP进行健康检查
            AgentServiceCheck check =new AgentServiceCheck();
            if (config.Scheme.Contains("tcp"))
            {
                check = new AgentServiceCheck
                {
                    DeregisterCriticalServiceAfter = config?.DeregisterCriticalServiceAfter,
                    Interval = config?.Interval,
                    TCP = $"{config?.HealCheckUrl}",
                    CheckID = $"{config?.Name}- {config?.Address}- {config?.Port}",
                };
            }
            else
            {
                check = new AgentServiceCheck()
                {
                    DeregisterCriticalServiceAfter = config?.DeregisterCriticalServiceAfter,//服务启动多久后注册
                    Interval = config?.Interval,//健康检查时间间隔
                    HTTP = config?.HealCheckUrl,//健康检查地址
                    Timeout = config?.Timeout,
                };
            }
           
            // 对Consul进行健康检查
            //AgentServiceCheck agentServiceCheck = new AgentServiceCheck();
            //agentServiceCheck.DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(10.0);
            //agentServiceCheck.Interval = TimeSpan.FromSeconds(10.0);
            //agentServiceCheck.HTTP = string.Format("{0}://{1}:{2}{3}", "http", config?.Address, config?.Port, "/consul/health/check");
           // checks[1] = agentServiceCheck;
            var registration = new AgentServiceRegistration()
            {
                ID = config?.Id.ToString(),
                Name = config?.Name,// 服务名
                Address = config ?.Address, // 服务绑定IP(也就是你这个项目运行的ip地址)
                Port = config ?.Port ?? 0, // 服务绑定端口(也就是你这个项目运行的端口)
                Check = check,
            };
            // 服务注册
            consulClient.Agent.ServiceRegister(registration).Wait();
            // 应用程序终止时，服务取消注册
            lifetime.ApplicationStopping.Register(() =>
            {
                consulClient.Agent.ServiceDeregister(registration.ID).Wait();
            });
            return app;
        }

        public static IApplicationBuilder MapHealthCheck(this IApplicationBuilder app)
        {
            app.Map("/consul/health/check", delegate (IApplicationBuilder s)
            {
                s.Run(async delegate (HttpContext context)
                {
                    await context.Response.WriteAsync("ok");
                });
            });
            return app;
        }

        // consul 自己的健康检查
        public static bool IsConsulActive(AppCousulConfig consulConfig)
        {
            ConsulClient consulClient = new ConsulClient(delegate (ConsulClientConfiguration option)
            {
                option.Address = new Uri("http://localhost:8500");
                option.Datacenter = "dc1";
            });
            try
            {
                consulClient.Health.Service("consul").GetAwaiter().GetResult();
                return true;
            }
            catch (HttpRequestException ex)
            {
                Console.WriteLine("Consule服务未启动:" + ex.Message);
            }
            catch (Exception ex2)
            {
                Console.WriteLine("Consule服务未启动:" + ex2.Message);
            }

            return false;
        }
    }
}